/****************************************************************************
 *
 *  ALi (Shanghai) Corporation, All Rights Reserved. 2003 Copyright (C)
 *
 *  File: p2p_upgrade.c
 *
 *  Description: This file contains the definition of ALi STB to STB upgrade.
 *  History:
 *      Date        	Author      	Version  		Comment
 *      ====        	======      =======  	=======
 *  1.  2005.2.18  Hong Zhang  	comext  		Initial
 *
 ****************************************************************************/
#include <types.h>
#include <retcode.h>
#include <sys_config.h>
#include <api/libc/printf.h>
#include <api/libc/string.h>
#include <bus/sci/sci.h>
#include <hld/hld_dev.h>
#include <osal/osal_timer.h>
#include <api/libchunk/chunk.h>
#include <api/libupg/p2p_upgrade.h>
#include <api/libc/fastCRC.h>

#ifdef  ENABLE_REMOTE_FLASH
#include <hld/sto/sto_dev.h>
#include <hld/sto/sto.h>
#endif
#include <hld/sto/sto.h>
#include <bus/flash/flash.h>
#ifdef ENABLE_EROM
#include <bus/erom/erom.h>
#include <bus/erom/uart.h>
#endif

#include "Packet.h"
#include "ErrorCode.h"
#include "UpgradeInterface.h"

#define P2PUPG_DBG(...) do{}while(0)
//#define P2PUPG_DBG soc_printf

//frank, add the macro to recuce the code size, disable the unused functions
#if(SYS_SDRAM_SIZE == 2)
#define ENABLE_UNUSED_FUNCTION 0
#else
#define ENABLE_UNUSED_FUNCTION 1
#endif

#define PACKAGE_SIZE 1024

#define MAX_RETRY_NUM 100

struct pan_device* LV_pPanDev;

CHUNK_LIST *pblock_list;
INT32 block_number;
CHUNK_HEADER *pslave_list;
CHUNK_LIST2 *pslave_reorg_list;

CHUNK_HEADER *pmaster_list = NULL; //store master chunks structure
INT32 master_blocks_number = 0;
static BOOL match_flag = FALSE;

INT32 slave_blocks_number;
INT32 slave_reorg_number;
UINT32 slave_Flash_type;
INT32 slave_status;
UINT32 slave_reorg_size;
UINT32 slave_burn_size;
UINT32 trans_size;
INT32 prog;
UINT8 msg[128];
UINT32 g_protocol_version = 0x30;

static BOOL is_burn_flash_3281();
static BOOL is_burn_otp_3281();
//frank,
static void (*callback_fun)(INT32 type, INT32 process, UINT8 *str) = NULL;
static UINT32 (*get_exit_key)(void) = NULL;
UINT32 p2p_uart_id = SCI_FOR_RS232;

#ifdef ENABLE_EROM
struct upge_feature_config g_upge_feature_config;
char* bk_buff;
INT32 upgrade_mode = 0;//0:Single 1:Multi

#define UART_DOWNLOAD_SPEED     0   // 1:2M, 2:6M, else 115200

#ifndef UPGRADE_FORMAT
#define UPGRADE_FORMAT  0
#endif

#ifndef BOOT_UPG
#define BOOT_UPG        1
#endif

#define TRANS_BLOCK_SIZE    0x80
#define FLASHWR_RUN_ADDR	0xa0000200
#define EROMCLIENT_RUN_ADDR    0xa0000200
#define EROMCLIENT_SEE_RUN_ADDR    0xa17d0200
#define FWCFG_START_ADDR    0xa001f000
#define IMAGE_START_ADDR    0xa0200000//0xa0020000

typedef struct _EROM_WM_COMMAND
{
    UINT32 Address;
    UINT32 Data;
}EROM_WM_COMMAND;

static EROM_WM_COMMAND m_SlaveConfig[] =
{
    {0xb8000081, 0x00}, 
#if 0//(SYS_SDRAM_SIZE == 2)
    {0xb8000082, 0x00}, 
    {0xb8000083, 0x14}, 
#else
    {0xb8000082, 0x05}, 
    {0xb8000083, 0x15}, 
#endif
    {0xb8000084, 0x05}, 
    {0xb8000085, 0x35}, 
    {0xb8000086, 0x33}, 
    {0xb8000087, 0x01}, 
    {0xb8000080, 0x00}, 
    {0xb8000080, 0x02}, 
    {0xb8000080, 0x03}, 
    {0xb8000080, 0x03}, 
    {0xb8000080, 0x03}, 
    {0xb8000080, 0x03}, 
    {0xb8000080, 0x03}, 
    {0xb8000080, 0x03}, 
    {0xb8000080, 0x03}, 
    {0xb8000080, 0x03}, 
    {0xb8000080, 0x01}, 
    {0xb8000081, 0x10}, 
//    {0xb8000029, 0x04}, 
};
static EROM_UPGRADE_PARAM m_UpgradeParam = 
{
    0, 0x80000, 0, 0, 
};
#if ((UPGRADE_FORMAT & BOOT_UPG) == BOOT_UPG)
BOOL toggle_flag = 0;
extern UINT8 BootUpgradeMode;
#endif
#endif

void p2p_uart_set_id(UINT32 uart_id)
{
	p2p_uart_id = uart_id;
	return;
	
}

static UINT8 m_allcode_include_bootloader = 0;

void p2p_enable_upgrade_bootloader(BOOL bEnable)
{
    if (bEnable)
        m_allcode_include_bootloader = 1;
    else
        m_allcode_include_bootloader = 0;
}

void pan_display_error(UINT32 nErrorCode)
{
	if(LV_pPanDev != NULL)
	{
		sprintf(msg,"e%3d", nErrorCode);
		pan_display(LV_pPanDev,  msg, 4);
	}
	
}

#if ( ((defined _S3281_) || (defined _M3503_)) && (defined _EROM_UPG_HOST_ENABLE_) )
static INT32 data_change_for_sto(INT32 data)
{
	/*
	 unsigned char buf[4];
	char *buf = &data;
	return (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3];
	*/
	INT32 tmp=0;
	tmp |= (data&0x000000ff)<<24;
	tmp |= (data&0x0000ff00)<<8;
	tmp |= (data&0x00ff0000)>>8;
	tmp |= (data&0xff000000)>>24;

	return tmp;
}

INT32 InitBlockList_3281()
{
#if (defined HDCP_IN_FLASH )
	UINT8 i=0;
	CHUNK_LIST *temp_pblock_list;
	INT32 temp_block_number=0,temp_block_number2=0; 
	UINT32 Block_id=0,HDCP_key_ID=0;
#ifdef 	HDCP_IN_FLASH
	HDCP_key_ID=HDCPKEY_CHUNK_ID;
#endif
#endif

		//because 3281 FW_ADDR use the DMX memery, so if 3281 Erom upg we should stop dmx first
		//close drivers	
		extern struct dmx_device  *g_dmx_dev;
		extern struct dmx_device  *g_dmx_dev2;
		dmx_stop( g_dmx_dev);
		dmx_close( g_dmx_dev);
		if (g_dmx_dev2)
		{
			dmx_stop(g_dmx_dev2);
			dmx_close(g_dmx_dev2);
		}

		// read flash data
		char* fw_addr = (char *)FW_ADDR;
		int transLen = FW_LEN;//need modify here
		UINT32 offset = 0x00;//get data from begin	
		sto_get_data( (struct sto_device *)dev_get_by_id(HLD_DEV_TYPE_STO, 0), fw_addr, offset, transLen);	
		P2PUPG_DBG("fw_addr=x%x\n", fw_addr); 
	
		chunk_init((UINT32)fw_addr, transLen);

#if 0    
	//==>change fw structure
    /*************************************************************************** 
	    Use "is_bk_chunk_valid" to judge whether CSTM use ALi chunk struct
	    If not use ALi chunk struct:
	    1.No need to change fw struct
	    2.No need to process uk backup
    ***************************************************************************/
		BOOL is_bk_backup_chunk_valid = FALSE; 
		UINT32 bk_encry_id = 0x07F80100;	
		UINT8 *bk_encry_addr = 0;
		CHUNK_HEADER bk_encry_hdr;
		UINT32 bk_plain_id = BK_PLAIN_CHUNK_ID;
		UINT8 *bk_plain_addr = 0;
		CHUNK_HEADER bk_plain_hdr;	
        UINT32 uk_encry_id = DECRYPT_KEY_ID;	
		UINT8 *uk_encry_addr;
		CHUNK_HEADER uk_encry_hdr;
        UINT32 uk_plain_id = UK_PLAIN_CHUNK_ID;
		UINT8 *uk_plain_addr;
		CHUNK_HEADER uk_plain_hdr;	
        UINT32 userdb_id = USER_DB_ID;	
		UINT8 *userdb_addr; 
		CHUNK_HEADER userdb_chuck_hdr;
        UINT32 eromclient_id = EROM_CLIENT_ID;	
		CHUNK_HEADER eromclient_chuck_hdr;	
        UINT32 eromclient_see_id = EROM_SEE_CLIENT_ID;	
		CHUNK_HEADER eromclient_see_chuck_hdr;	
        if(get_chunk_header(bk_plain_id,&bk_plain_hdr))
        {
            is_bk_backup_chunk_valid = TRUE;
        }
        if(is_bk_backup_chunk_valid)
        {
            get_chunk_header(bk_encry_id,&bk_encry_hdr);
			bk_encry_addr = chunk_goto(&bk_encry_id,0xFFFFFFFF,1);	
			P2PUPG_DBG("uk_encry_addr=x%x\n", bk_encry_addr); 
			
			get_chunk_header(bk_plain_id,&bk_plain_hdr);
			bk_plain_addr = chunk_goto(&bk_plain_id,0xFFFFFFFF,1);	
			P2PUPG_DBG("uk_plain_addr=x%x\n", bk_plain_addr); 

    		get_chunk_header(uk_encry_id,&uk_encry_hdr);
    		uk_encry_addr = chunk_goto(&uk_encry_id,0xFFFFFFFF,1);	
    		P2PUPG_DBG("uk_encry_addr=x%x\n", uk_encry_addr); 
    		
    		get_chunk_header(uk_plain_id,&uk_plain_hdr);
    		uk_plain_addr = chunk_goto(&uk_plain_id,0xFFFFFFFF,1);	
    		P2PUPG_DBG("uk_plain_addr=x%x\n", uk_plain_addr); 
    			
    		get_chunk_header(userdb_id,&userdb_chuck_hdr);
            userdb_addr = chunk_goto(&userdb_id,0xFFFFFFFF,1);
		    P2PUPG_DBG("userdb_addr=x%x\n", userdb_addr); 
    		
    		get_chunk_header(eromclient_id,&eromclient_chuck_hdr);
    		get_chunk_header(eromclient_see_id,&eromclient_see_chuck_hdr);
    			
    		//copy plain uk to encry uk 	
    		MEMCPY(uk_encry_addr+CHUNK_HEADER_SIZE, uk_plain_addr+CHUNK_HEADER_SIZE, uk_encry_hdr.offset-CHUNK_HEADER_SIZE);

			//copy plain bk to encry bk 	
			MEMCPY(bk_encry_addr+CHUNK_HEADER_SIZE, bk_plain_addr+CHUNK_HEADER_SIZE, bk_encry_hdr.offset-CHUNK_HEADER_SIZE);

            //delete plain_uk/plain bk/eromclient/eromclient_see chunk 
        	userdb_chuck_hdr.len += 0x80000;//enlarge 8 sector because we delete 8 sector
        	P2PUPG_DBG("userdb_chuck_hdr.len=x%x\n", userdb_chuck_hdr.len); 
        	INT32 new_userdb_len = data_change_for_sto(userdb_chuck_hdr.len);//len
        	MEMCPY(userdb_addr+CHUNK_LENGTH, &new_userdb_len, 4);
        	P2PUPG_DBG("userdb_addr=x%x\n", userdb_addr); 
        	MEMCPY(bk_plain_addr, userdb_addr, CHUNK_HEADER_SIZE);//copy userdb to plain bk chunk
        	UINT32 delete_len = (userdb_chuck_hdr.len - 0x70);
        	MEMSET(bk_plain_addr+CHUNK_HEADER_SIZE, 0xFF, delete_len);
        	P2PUPG_DBG("delete from x%x to 0x%x\n", bk_plain_addr+CHUNK_HEADER_SIZE, bk_plain_addr+CHUNK_HEADER_SIZE+delete_len); 
        }
    //==>new fw ok	
#endif    
	
		
		block_number = chunk_count(0,0);
		if(block_number <= 0 )
			return !SUCCESS;
	
		FreeBlockList();
	
	//	P2PUPG_DBG("p2p: alloc block list!!!\n");
		pblock_list = (CHUNK_LIST *)MALLOC(sizeof(CHUNK_LIST)*block_number);
		if(pblock_list == NULL)
			return !SUCCESS;
	
	//	if(!get_chunk_list(pblock_list))
		if(!get_chunk_list(pblock_list))
		{
			FREE(pblock_list);
			pblock_list = NULL;
			return !SUCCESS;
		}
#ifdef HDCP_IN_FLASH
		if(m_allcode_include_bootloader==1)
			return SUCCESS;
		
		(temp_pblock_list)= (CHUNK_LIST *)MALLOC(sizeof(CHUNK_LIST)*block_number);
		
		for(i=0;i<block_number;i++)
			{
				if(((UINT32 )pblock_list[i].id)!=HDCP_key_ID)
				{			
					MEMCPY((temp_pblock_list+temp_block_number),(pblock_list+i),sizeof(CHUNK_LIST));
					temp_block_number++;
				}
			}
		FREE(pblock_list);
		block_number=temp_block_number;
		pblock_list = (CHUNK_LIST *)MALLOC(sizeof(CHUNK_LIST)*block_number);
		MEMCPY(pblock_list,temp_pblock_list,sizeof(CHUNK_LIST)*block_number);
		FREE(temp_pblock_list);
#endif
	
		return SUCCESS;

}

INT32 InitBlockList()	
{
	return InitBlockList_3281();
}
#else
INT32 InitBlockList()	
{
#if (defined HDCP_IN_FLASH )
	UINT8 i=0;
	CHUNK_LIST *temp_pblock_list;
	INT32 temp_block_number=0,temp_block_number2=0; 
	UINT32 Block_id=0,HDCP_key_ID=0;
#ifdef 	HDCP_IN_FLASH
	HDCP_key_ID=HDCPKEY_CHUNK_ID;
#endif
#endif

	sto_chunk_init(0, 0);

//	block_number = chunk_count(0,0);
	block_number = sto_chunk_count(0,0);
	if(block_number <= 0 )
		return !SUCCESS;

	FreeBlockList();

//	P2PUPG_DBG("p2p: alloc block list!!!\n");
	pblock_list = (CHUNK_LIST *)MALLOC(sizeof(CHUNK_LIST)*block_number);
	if(pblock_list == NULL)
		return !SUCCESS;
#if((defined _VMX_CA_ENABLE_) && (defined _EROM_UPG_HOST_ENABLE_)&& ((defined _S3281_) ||(defined _M3503_)) ) 
	if(!get_chunk_list(pblock_list))
#else
	if(!sto_get_chunk_list(pblock_list))
#endif
	{
		FREE(pblock_list);
		pblock_list = NULL;
		return !SUCCESS;
	}
#ifdef HDCP_IN_FLASH
	if(m_allcode_include_bootloader==1)
		return SUCCESS;
	
	(temp_pblock_list)= (CHUNK_LIST *)MALLOC(sizeof(CHUNK_LIST)*block_number);
	
	for(i=0;i<block_number;i++)
		{
			if(((UINT32 )pblock_list[i].id)!=HDCP_key_ID)
			{			
				MEMCPY((temp_pblock_list+temp_block_number),(pblock_list+i),sizeof(CHUNK_LIST));
				temp_block_number++;
			}
		}
	FREE(pblock_list);
	block_number=temp_block_number;
	pblock_list = (CHUNK_LIST *)MALLOC(sizeof(CHUNK_LIST)*block_number);
	MEMCPY(pblock_list,temp_pblock_list,sizeof(CHUNK_LIST)*block_number);
	FREE(temp_pblock_list);
#endif

	return SUCCESS;
}
#endif



void FreeBlockList()
{
	if(pblock_list != NULL)
	{
//		P2PUPG_DBG("p2p: free block list!!!\n");
		FREE(pblock_list);
		pblock_list = NULL;
	}
}

void FreeSlavelist()
{
#ifdef ENABLE_EROM
    if(g_upge_feature_config.sys_sdram_size>2)
    {
        if(bk_buff != NULL)
        {
            FREE(bk_buff);
            bk_buff = NULL;
        }
    }
#endif
	if(pslave_list != NULL)
	{
//		P2PUPG_DBG("p2p: free slave list!!!\n");
		FREE(pslave_list);
		pslave_list = NULL;
	}

	if(pslave_reorg_list != NULL)
	{
//		P2PUPG_DBG("p2p: free slave reorg list!!!\n");
		FREE(pslave_reorg_list);
		pslave_reorg_list = NULL;
	}
}

UINT32 Index2Id(INT32 index)
{
	if(pblock_list == NULL)
		return 0;
	if(index >= block_number)
		return 0;

	return pblock_list[index]. id;
}

void ClearUpgFlag()
{
	INT32 i;

	if(pblock_list == NULL)
		return;

	for(i=0; i<block_number; i++)
		pblock_list[i].upg_flag = 0;
}

INT32 SetUpgFlag(UINT32 id, UINT32 mask, INT32 flag)
{
	INT32 i;
	INT32 flag_update;

	if(pblock_list == NULL)
		return !SUCCESS;

	flag_update = FALSE;
	for(i=0; i<block_number; i++)
	{
		if (!((id ^ pblock_list[i].id) & mask))
		{
			pblock_list[i].upg_flag = flag;
			flag_update = TRUE;
		}
	}

	if(!flag_update)
		return !SUCCESS;

	return SUCCESS;
}

void p2p_delay(void)
{
    osal_delay(50000);
    osal_delay(50000);
}

void p2p_delay_10ms(void)
{
	osal_delay(10000);
}

static INT32 IsInSlave(unsigned int id)
{
	int i;

	for(i=0; i<slave_blocks_number; i++)
	{
		if(pslave_list[i].id == id)
			return SUCCESS;
	}

	return !SUCCESS;
}

static INT32 IsUpgBootloader(UINT8* sVer)
{
#if ( ((defined _M3503_)&&(defined(_EROM_UPG_HOST_ENABLE_)) ) || (SYS_PROJECT_FE == PROJECT_FE_DVBT && SYS_SDRAM_SIZE == 2) )
#else
	UINT8 *upg_bootloader="upgboot";

#ifdef FORCE_UPGRADE_OLD_PROTOCOL_BOOTLOADER
	// if upgrade protocol version is old protocol version 
	// force upgrade bootloader
	
	if(g_protocol_version < NEW_PROTOCOL_VERSION)
		return SUCCESS;
#endif	
	if(STRCMP(&sVer[8], upg_bootloader) != 0)
		return !SUCCESS;
#endif
	return SUCCESS;
}

static INT32 SlaveReorg(void (*callback)(INT32 type, INT32 process, UINT8 *str))
{
		UINT32 len,offset;
	//	UINT8* p;
		UINT32 chunk_pos;
		INT32 i,j; 
		BOOL all_upg_flag = TRUE;
#ifdef FORCE_UPGRADE_OLD_PROTOCOL_BOOTLOADER
		BOOL force_upgrade = FALSE;
#endif

	slave_reorg_size = 0;
	slave_burn_size = 0;

#ifdef FORCE_UPGRADE_OLD_PROTOCOL_BOOTLOADER
	// if upgrade protocol version is old protocol version 
	// and upgrade chunk include maincode or second loader
	// force upgrade bootloader
	if(g_protocol_version < NEW_PROTOCOL_VERSION)
	{
		for(i=1; i<block_number; i++)
		{
			if(pblock_list[i].upg_flag && 
				(((pblock_list[i].id & 0xFFFF0000) == 0x01FE0000)
				|| ((pblock_list[i].id & 0xFFFF0000) == 0x00FF0000)))
			{
				force_upgrade = TRUE;
				break;
			}
		}
		if(force_upgrade)
			pblock_list[0].upg_flag = 1;
	}

#endif

	for(i=1; i<block_number; i++)
	{
		if(pblock_list[i].upg_flag != 1)
		{
			all_upg_flag = FALSE;
			break;
		}
	}

#ifdef HDCP_IN_FLASH
    if( (!all_upg_flag)&&(!match_flag))
    {
        callback_fun(2,0,"STB firmware is not compatible, use allcode");
        return !SUCCESS;
    }
#endif
	
	if((block_number != slave_blocks_number) && (!all_upg_flag))
	{
		return !SUCCESS;
	}
	if(all_upg_flag)
	{
		slave_reorg_number = block_number;

		pslave_reorg_list = (CHUNK_LIST2 *)MALLOC(sizeof(CHUNK_LIST2)*slave_reorg_number);
		if(pslave_reorg_list == NULL) return !SUCCESS;

		chunk_pos = sto_chunk_goto(&pblock_list[0].id, 0xFFFFFFFF, 1);
		offset = sto_fetch_long(chunk_pos + CHUNK_OFFSET);

		pslave_reorg_list[0].type = 1;  //move
		pslave_reorg_list[0].index= 0;
		pslave_reorg_list[0].offset = offset;

		for(i=1; i<block_number; i++)
		{
			chunk_pos = sto_chunk_goto(&pblock_list[i].id, 0xFFFFFFFF, 1);
			offset = sto_fetch_long(chunk_pos + CHUNK_OFFSET);
			pslave_reorg_list[i].type = 2;  //transfer
			pslave_reorg_list[i].index= i;
			pslave_reorg_list[i].offset = offset;
		}
	}
	else
	{
		slave_reorg_number = slave_blocks_number;
		for(i=1; i<block_number; i++)
		{
			if(pblock_list[i].upg_flag)
			{
				if(IsInSlave(pblock_list[i].id) != SUCCESS)
				{	
					return !SUCCESS;//slave_reorg_number++;   //add chunk
				}
			}
			else
			{
				if(slave_status != 0)
				{
					callback(2,0,"Slave data has been destroyed, please upgrade allcode.");
					return !SUCCESS;
				}
			}
		}

		pslave_reorg_list = (CHUNK_LIST2 *)MALLOC(sizeof(CHUNK_LIST2)*slave_reorg_number);
		if(pslave_reorg_list == NULL) return !SUCCESS;

		/*init pslave_reorg_list*/
		for(i=0; i<slave_reorg_number; i++)
		{
			pslave_reorg_list[i].type = 1;  //move chunk
			pslave_reorg_list[i].index= i;
			pslave_reorg_list[i].offset = pslave_list[i].offset;
		}

		for(i=1; i<block_number; i++)
		{
			if(pblock_list[i].upg_flag)
			{
				chunk_pos = sto_chunk_goto(&pblock_list[i].id, 0xFFFFFFFF, 1);
				offset = sto_fetch_long(chunk_pos + CHUNK_OFFSET);

				/*replace chunk*/
				for(j=0; j<slave_blocks_number; j++)
				{
					if(pslave_reorg_list[j].type == 1 && pslave_list[pslave_reorg_list[j].index].id == pblock_list[i].id)
					{
	                /*
	                //frank disnable
#if (SYS_CHIP_MODULE == ALI_M3327C && SYS_SDRAM_SIZE == 2)
						if(ID_TYPE(pblock_list[i].id)!=TEMPDB_ID || slave_status!=0)
#endif
	                */
						{
							pslave_reorg_list[j].type = 2;  //transfer
							pslave_reorg_list[j].index= i;
							pslave_reorg_list[j].offset = offset;
						}
						break;
					}
				}
			}
		}
	}
	/*upgrade bootloader*/
	if(((IsUpgBootloader(pslave_list[0].version)==SUCCESS) || m_allcode_include_bootloader) && (pblock_list[0].upg_flag==1))
	{
		chunk_pos = sto_chunk_goto(&pblock_list[0].id, 0xFFFFFFFF, 1);
		offset = sto_fetch_long(chunk_pos + CHUNK_OFFSET);

		pslave_reorg_list[0].type = 2;  //transfer
		pslave_reorg_list[0].index= 0;
		pslave_reorg_list[0].offset = offset;

		slave_reorg_size += offset;
		slave_burn_size += offset;
	}

	for(i=1; i<slave_reorg_number; i++)
	{
		if(pslave_reorg_list[i].type  == 1) //move
		{
            // Jie Wu, disable below line to let the progress bar move smoothly.
			//slave_reorg_size += pslave_list[pslave_reorg_list[i].index].len+16;
			if(pslave_reorg_list[i].offset == 0)
				slave_burn_size += pslave_list[pslave_reorg_list[i].index].len+16;
			else
				slave_burn_size += pslave_reorg_list[i].offset;
		}
		else //transfer
		{
			chunk_pos = sto_chunk_goto(&pblock_list[pslave_reorg_list[i].index].id, 0xFFFFFFFF, 1);
			len = sto_fetch_long(chunk_pos + CHUNK_OFFSET);
			if(len == 0)
				len = sto_fetch_long(chunk_pos + CHUNK_LENGTH) + 16;
			slave_reorg_size += len;

			if(pslave_reorg_list[i].offset == 0)
				slave_burn_size += len ;
			else
				slave_burn_size += pslave_reorg_list[i].offset;
		}
	}

	if(pslave_reorg_list[0].type == 2)  //transfer bootloader
	{
		if(slave_burn_size > slave_Flash_type)
		{
			callback(2,0,"Upgrade data too large, failed.");
			return !SUCCESS;
		}
	}
	else
	{
		if(pslave_list[0].offset+slave_burn_size > slave_Flash_type)
		{
			callback(2,0,"Upgrade data too large, failed.");
			return !SUCCESS;
		}
	}
	return SUCCESS;
}

static INT32 SlaveReorg_3281(void (*callback)(INT32 type, INT32 process, UINT8 *str))
{
#if ( ((defined _S3281_) || (defined _M3503_)) && (defined(_EROM_UPG_HOST_ENABLE_)) )
		UINT32 len,offset;
	//	UINT8* p;
		UINT32 chunk_pos;
		INT32 i,j; 
		BOOL all_upg_flag = TRUE;
#ifdef FORCE_UPGRADE_OLD_PROTOCOL_BOOTLOADER
		BOOL force_upgrade = FALSE;
#endif

	slave_reorg_size = 0;
	slave_burn_size = 0;

	slave_reorg_number = block_number;
#if((defined _VMX_CA_ENABLE_) && (defined _EROM_UPG_HOST_ENABLE_)&& ((defined _S3281_) ||(defined _M3503_)) ) 
	slave_reorg_number -= 1;
#endif
	pslave_reorg_list = (CHUNK_LIST2 *)MALLOC(sizeof(CHUNK_LIST2)*slave_reorg_number);
	if(pslave_reorg_list == NULL) return !SUCCESS;

	chunk_pos = (UINT32)chunk_goto(&pblock_list[0].id, 0xFFFFFFFF, 1);
	offset = fetch_long((unsigned char *)(chunk_pos + CHUNK_OFFSET));

	pslave_reorg_list[0].type = 1;	//move
	pslave_reorg_list[0].index= 0;
	pslave_reorg_list[0].offset = offset;

#if((defined _VMX_CA_ENABLE_) && (defined _EROM_UPG_HOST_ENABLE_)&& ((defined _S3281_) ||(defined _M3503_)) ) 
	for(i=1; i<block_number-1; i++)
#else
	for(i=1; i<block_number; i++)
#endif
	{
		chunk_pos = (UINT32)chunk_goto(&pblock_list[i].id, 0xFFFFFFFF, 1);
		offset = fetch_long((unsigned char *)(chunk_pos + CHUNK_OFFSET));
		pslave_reorg_list[i].type = 2;	//transfer
		pslave_reorg_list[i].index= i;
		pslave_reorg_list[i].offset = offset;
	}
	
	/*upgrade bootloader*/
	if(((IsUpgBootloader(pslave_list[0].version)==SUCCESS) || m_allcode_include_bootloader) && (pblock_list[0].upg_flag==1))
	{
		chunk_pos =(UINT32)chunk_goto(&pblock_list[0].id, 0xFFFFFFFF, 1);
		offset = fetch_long((unsigned char *)(chunk_pos + CHUNK_OFFSET));

		pslave_reorg_list[0].type = 2;	//transfer
		pslave_reorg_list[0].index= 0;
		pslave_reorg_list[0].offset = offset;

		slave_reorg_size += offset;
		slave_burn_size += offset;
	}

	for(i=1; i<slave_reorg_number; i++)
	{
		if(pslave_reorg_list[i].type  == 1) //move
		{
			// Jie Wu, disable below line to let the progress bar move smoothly.
			//slave_reorg_size += pslave_list[pslave_reorg_list[i].index].len+16;
			if(pslave_reorg_list[i].offset == 0)
				slave_burn_size += pslave_list[pslave_reorg_list[i].index].len+16;
			else
				slave_burn_size += pslave_reorg_list[i].offset;
		}
		else //transfer
		{
			chunk_pos = (UINT32)chunk_goto(&pblock_list[pslave_reorg_list[i].index].id, 0xFFFFFFFF, 1);
			len = fetch_long((unsigned char *)(chunk_pos + CHUNK_OFFSET));
			if(len == 0)
				len = fetch_long((unsigned char *)(chunk_pos + CHUNK_LENGTH)) + 16;
			slave_reorg_size += len;

			if(pslave_reorg_list[i].offset == 0)
				slave_burn_size += len ;
			else
				slave_burn_size += pslave_reorg_list[i].offset;
		}
	}
#endif
	return SUCCESS;	
}

//check if master and slave`s chunk structure is same
//if not, match_flag is 0,or else match_flag is 1
static void set_match_chunk_flag()
{
    UINT32 i = 0;
    UINT32 chid = 0;

    sto_chunk_init(0, 0);
    master_blocks_number = sto_chunk_count(0, 0);
    if(master_blocks_number != slave_blocks_number)
    {
        return ;
    }
    pmaster_list = (CHUNK_HEADER *)MALLOC(master_blocks_number*sizeof(CHUNK_HEADER));
    if(NULL == pmaster_list)
    {
        return ;
    }
    //init master chunk_header
    for (i = 1; i <= master_blocks_number; i++)
    {
        sto_chunk_goto(&chid, 0, i);
        sto_get_chunk_header(chid, pmaster_list+i-1);
    }
    //compare master and slave`s structure
    for(i=0; i<master_blocks_number; i++)
    {
        if((pslave_list[i].id != pmaster_list[i].id) ||(pslave_list[i].offset != pmaster_list[i].offset))
        {
            FREE(pmaster_list);
            pmaster_list = NULL;
            return;
        }
    }
    FREE(pmaster_list);
    pmaster_list = NULL;
    match_flag = TRUE;
}
static INT32 CheckVersion(UINT8* sVer, UINT8* hVer)
{
	UINT8 sVersion[16], hVersion[16];

	STRCPY(sVersion, sVer);
	STRCPY(hVersion, hVer);
	sVersion[8] = '\0';
	hVersion[8] = '\0';

	if(STRCMP(sVersion, hVersion) != 0)
		return !SUCCESS;

	return SUCCESS;
}

UINT32 GetChunk(BYTE *buffer, UINT32 nLen)
{
	UINT8 *p, *pblock;
	UINT32 chunk_pos;
	struct sto_device *sto_dev = NULL;
	UINT8 sVer[16], hVer[16];
	INT32 i = 0;
#if (defined HDCP_IN_FLASH )
	INT32 temp_slave_blocks_number=0;
	CHUNK_HEADER *temp_pslave_list = NULL;
#endif
	
	switch((unsigned int)buffer[0])
	{
		case 1:
		case 2:
		case 7:
		case 10:
			slave_Flash_type = 0x80000;	//flash size
			break;
		case 3:
		case 4:
		case 8:
		case 9:
		case 11:
		case 13:
			slave_Flash_type = 0x100000;
			break;
		case 5:
		case 6:
		case 12:
		case 14:
		case 15:
		case 16:
		case 25:
		case 28:
		case 30:
			slave_Flash_type = 0x200000;
			break;
		case 17:
		case 18:
		case 19:
		case 33:
			slave_Flash_type = 0x400000;
			break;
             case 31:
             case 38:
			slave_Flash_type = 0x800000;
			break;
		default:
			slave_Flash_type = 0x200000;/*For unkown flash type,default is 2M*/
			//return !SUCCESS;
	}

	slave_status = (unsigned int)buffer[1];
	if(slave_status==0)
		slave_blocks_number = (nLen -2)/CHUNK_HEADER_SIZE;
	else
		slave_blocks_number = 1;

	pslave_list= (CHUNK_HEADER *)MALLOC(sizeof(CHUNK_HEADER)*slave_blocks_number);
	if (pslave_list == NULL)
		return !SUCCESS;
	MEMSET((void *)pslave_list,0,sizeof(CHUNK_HEADER)*slave_blocks_number);

#if (defined HDCP_IN_FLASH )
#ifdef  HDCP_IN_FLASH
	if(m_allcode_include_bootloader==0)
#endif		
		{
			temp_pslave_list= (CHUNK_HEADER *)MALLOC(sizeof(CHUNK_HEADER)*slave_blocks_number);
			if (temp_pslave_list == NULL)
				return !SUCCESS;
			MEMSET((void *)temp_pslave_list,0,sizeof(CHUNK_HEADER)*slave_blocks_number);
		}
#endif

	pblock = &buffer[2];
	for(i=0; i<slave_blocks_number; i++)
	{
		p = pblock + CHUNK_ID;
		pslave_list[i].id = (*p<<24)+(*(p+1)<<16)+(*(p+2)<<8)+(*(p+3)<<0);

		p = pblock + CHUNK_LENGTH;
		pslave_list[i].len = (*p<<24)+(*(p+1)<<16)+(*(p+2)<<8)+(*(p+3)<<0);

		p = pblock + CHUNK_OFFSET;
		pslave_list[i].offset = (*p<<24)+(*(p+1)<<16)+(*(p+2)<<8)+(*(p+3)<<0);

		p = pblock + CHUNK_CRC;
		pslave_list[i].crc = (*p<<24)+(*(p+1)<<16)+(*(p+2)<<8)+(*(p+3)<<0);

		p = pblock + CHUNK_NAME;
		STRCPY((char *)pslave_list[i].name, (char *)p);

		p = pblock + CHUNK_VERSION;
		STRCPY((char *)pslave_list[i].version, (char *)p);

		p = pblock + CHUNK_TIME;
		STRCPY((char *)pslave_list[i].time, (char *)p);

#if (defined HDCP_IN_FLASH )
#ifdef HDCP_IN_FLASH
		if(m_allcode_include_bootloader==0)
#endif		
		{
			UINT32 special_type = 0;

#ifdef HDCP_IN_FLASH		
			if(pslave_list[i].id == HDCPKEY_CHUNK_ID)
			{
				special_type =1;
			}
#endif			
			if(special_type!=1)
			{
				MEMCPY((temp_pslave_list+temp_slave_blocks_number),(pslave_list+i),sizeof(CHUNK_HEADER));
				temp_slave_blocks_number++;			
			}
			else
			{ 
				if(i > 0)
				{
					temp_pslave_list[i-1].offset=(temp_pslave_list[i-1].offset+pslave_list[i].offset);
				}
			}
		}
#endif

		pblock += CHUNK_HEADER_SIZE;
	}

#if (defined HDCP_IN_FLASH)
#ifdef  HDCP_IN_FLASH
		if(m_allcode_include_bootloader==0)
#endif		
		{
		       set_match_chunk_flag();
			FREE(pslave_list);
			slave_blocks_number=temp_slave_blocks_number;
			pslave_list = (CHUNK_HEADER *)MALLOC(sizeof(CHUNK_HEADER)*slave_blocks_number);
			MEMCPY(pslave_list,temp_pslave_list,sizeof(CHUNK_HEADER)*slave_blocks_number);
			FREE(temp_pslave_list);
		}
#endif


	STRCPY(sVer, pslave_list[0].version);
	chunk_pos = sto_chunk_goto(&pblock_list[0].id, 0xFFFFFFFF, 1);
	sto_dev = (struct sto_device*)dev_get_by_id(HLD_DEV_TYPE_STO, 0);
	sto_open(sto_dev);
	sto_lseek(sto_dev, chunk_pos+CHUNK_VERSION, STO_LSEEK_SET);
	sto_read(sto_dev, hVer, 16);
	//sto_close(sto_dev);

#ifdef FORCE_UPGRADE_OLD_PROTOCOL_BOOTLOADER
	if(g_protocol_version < NEW_PROTOCOL_VERSION)
		return SUCCESS;
#endif
	if(CheckVersion(sVer, hVer) != SUCCESS)
	{
		callback_fun(2,0,"STB version is not compatible.");
		return !SUCCESS;
	}
}



static INT32 command_address (void (*callback)(INT32 type, INT32 process, UINT8 *str))
{
	UINT32 addr;


	if(pslave_reorg_list[0].type == 2)  //transfer bootloader
	{
		addr = 0x0;
	}
	else
	{
#if (SYS_PROJECT_FE	== PROJECT_FE_DVBT && SYS_SDRAM_SIZE == 2)
		addr = 0x7800;
#else
#if (SYS_CHIP_MODULE == ALI_M3327C && SYS_SDRAM_SIZE == 2)
		//addr = 0xc000;
		//add logo data, so the address is changed
        addr = 0x8000;
#else
		addr = pslave_list[0].offset;
#endif
#endif
	}

	return (INT32)cmd_address(addr);
}


static INT32 command_move (INT32 index, UINT32 offset, void (*callback)(INT32 type, INT32 process, UINT8 *str))
{
	INT32 result = (INT32)cmd_move(pslave_list[index].id, offset);
	if(result == SUCCESS)
	{
		INT32 progress = trans_size*100/slave_reorg_size;
		if(progress > prog)
		{
			prog = progress;
			callback(1,prog,NULL);
			if(prog<100)
			{
#if (SYS_CHIP_MODULE != ALI_M3327C || SYS_SDRAM_SIZE != 2)
				sprintf(msg,"u%d  ",prog);
				pan_display(LV_pPanDev,  msg, 4);
#endif
			}
		}
	}
	return result;
}

static void UpgradeProgress(unsigned int nPercent)
{

	trans_size += nPercent;
	INT32 progress = trans_size*100/slave_reorg_size;
	if(progress > prog)
	{
		prog = progress;
		callback_fun(1,prog,NULL);
#if (SYS_CHIP_MODULE != ALI_M3327C || SYS_SDRAM_SIZE != 2)
		if(prog<100)
		{
			sprintf(msg,"u%d  ",prog);
			pan_display(LV_pPanDev,  msg, 4);
		}
#endif
	}
				
//	callback_fun(1,nPercent, NULL);	
}
static INT32 command_transfer (INT32 index, void (*callback)(INT32 type, INT32 process, UINT8 *str))
{
	UINT32 id,transLen=0;
	UINT32 chunk_pos;
	BYTE *p = NULL;
	struct sto_device* sto_dev = NULL;
	
	id = pblock_list[index].id;
	chunk_pos = sto_chunk_goto(&id, 0xFFFFFFFF, 1);

	transLen = sto_fetch_long(chunk_pos + CHUNK_OFFSET);
	if(transLen == 0)
		transLen = sto_fetch_long(chunk_pos + CHUNK_LENGTH) + 16;

	if (chunk_pos == (UINT32)ERR_PARA || chunk_pos == (UINT32)ERR_FAILUE)
	{
		callback(2,0,"Error #601");
		return !SUCCESS;
	}

	p = ((unsigned char *)FLASH_BASE) + chunk_pos;
	
	
	return (INT32)cmd_transfer(p, transLen, UpgradeProgress, get_exit_key);
}

static INT32 command_transfer_3281_new(void (*callback)(INT32 type, INT32 process, UINT8 *str))
{
#if ( ((defined _S3281_) || (defined _M3503_)) && (defined(_EROM_UPG_HOST_ENABLE_)) )
	UINT32 id,transLen=0;
	UINT32 chunk_pos;
	BYTE *p = NULL;

	chunk_pos = FW_ADDR;
	transLen = FW_LEN;

	if (chunk_pos == (UINT32)ERR_PARA || chunk_pos == (UINT32)ERR_FAILUE)
	{
		callback(2,0,"Error #601");
		return !SUCCESS;
	}

	p = (BYTE *)chunk_pos;
	P2PUPG_DBG("p:0x%x\n", p);
	
	return (INT32)cmd_transfer(p, transLen, UpgradeProgress, get_exit_key);
#endif
}


static void BurnProgress(unsigned int nPercent)
{
	callback_fun(1,nPercent, NULL);
	if(nPercent<100)
	{
		sprintf(msg,"b%d  ",nPercent);
		pan_display(LV_pPanDev,  msg, 4);
	}
}
static INT32 command_burn_new(void (*callback)(INT32 type, INT32 process, UINT8 *str), BOOL bCareReturn)
{
	
	return (INT32)cmd_burn(slave_burn_size, BurnProgress, bCareReturn);
}

static INT32 command_reboot(void (*callback)(INT32 type, INT32 process, UINT8 *str))
{

	return (INT32)cmd_reboot();
}

#ifdef ENABLE_EROM

void config_upge_feature(struct upge_feature_config *pupge_feature_config)
{
    if(NULL == pupge_feature_config)
    {
        ASSERT(0);
    }
	else
		MEMCPY(&g_upge_feature_config, pupge_feature_config, sizeof(struct upge_feature_config));

    bk_buff = g_upge_feature_config.bk_buff;

    g_upge_feature_config.enable_fast_erom_upgrade = TRUE;
//    g_upge_feature_config.InitBlockList = InitBlockList_fast;
//    g_upge_feature_config.FreeBlockList = FreeBlockList_fast;
//    g_upge_feature_config.FreeSlavelist = FreeSlavelist_fast;
//    g_upge_feature_config.Index2Id = Index2Id_fast;
//    g_upge_feature_config.ClearUpgFlag = ClearUpgFlag_fast;
//    g_upge_feature_config.SetUpgFlag = SetUpgFlag_fast;
//    g_upge_feature_config.p2p_delay = NULL;
//    
//    g_upge_feature_config.sys_upgrade = sys_upgrade_fast;
//    g_upge_feature_config.SetUpgradeMode = SetUpgradeMode_fast;
    
}

void sync_twinkle()
{
#if((_DVB_T_TARGET_BOARD==HW_ALiG00_BOARD_M3101) ||(_DVB_T_TARGET_BOARD==HW_ALiA00_3101_BOARD))
#if ((UPGRADE_FORMAT & BOOT_UPG) == BOOT_UPG)
	toggle_flag = (toggle_flag ? 0:1);
	Upgrade_Twinkle(toggle_flag);
	osal_task_sleep(1);
#endif
#endif
}

void transfer_twinkle()
{
#if((_DVB_T_TARGET_BOARD==HW_ALiG00_BOARD_M3101) ||(_DVB_T_TARGET_BOARD==HW_ALiA00_3101_BOARD))
#if ((UPGRADE_FORMAT & BOOT_UPG) == BOOT_UPG)
	toggle_flag = (toggle_flag ? 0:1);
	Upgrade_Twinkle(toggle_flag);
	Power_RemoteLedOnOff(toggle_flag);
	osal_task_sleep(1);
#endif
#endif
}

void  SetUpgradeMode(INT32 mode)
{
    upgrade_mode = mode;
}

static void init_buffer()
{
#if (SYS_SDRAM_SIZE != 2) || defined(_MHEG5_ENABLE_)
    bk_buff = (char *)MALLOC(0x10000);
#endif
}

static void free_buffer()
{
#if (SYS_SDRAM_SIZE != 2) || defined(_MHEG5_ENABLE_)
    if(bk_buff != NULL)
    {
        FREE(bk_buff);
        bk_buff = NULL;
    }
#endif
}

static BOOL sync_slave(UINT8 mode, UINT32 sync_tmo)
{
    INT32 result, user_int, retry_count = 0;

    if(UPGRADE_MULTI == upgrade_mode)
        callback_fun(3, 0, "When slaves ready, press \"OK\" to continue...");
    else
	    callback_fun(3, 0, "Synchronizing...");

    while(1)
    {
	 
		sync_twinkle(); 
		result = erom_sync(sync_tmo, mode);
	 
	    if(SUCCESS == result && UPGRADE_MULTI != upgrade_mode)
	    {
	        callback_fun(3, 0, "Synchronize OK.");
            break;
	    }
        else
           callback_fun(3, 0, "Please reset target!");  

        user_int = get_exit_key();
		if(1 == user_int)
		{
			callback_fun(2, 0, "Upgrade aborted.");
			return FALSE;
		}

        if(UPGRADE_MULTI == upgrade_mode)
        {
            if(2 == user_int)
            {
		  callback_fun(3, 0, "Synchronize OK.");
                break;
            }
        }
        else
        {
    		retry_count++;
    		if(retry_count > MAX_RETRY_NUM*10)
    		{
    			callback_fun(2, 0, "Synchronization failed.");
    			return FALSE;
    		}
    		if(!(retry_count%10))
    		{
    			sprintf(msg, "Synchronization time out, retry %d", retry_count/10);
    			callback_fun(2, 0, msg);
    		}
        }
    }
//    unsigned char data8 = 0x6;
//    erom_wm(0xB800009B,&data8,1,0);
    return TRUE;
}

static BOOL send_upgrade_param(UINT32 offset)
{
    UINT32 data_check, data_send;
    int retry_times = 3;

    data_send = *((UINT32 *)&m_UpgradeParam + offset/sizeof(UINT32));
    while(retry_times--)
    {
        erom_wm(UPGRADE_PARAM_ADDR+offset, &data_send, sizeof(UINT32), 0);
        P2PUPG_DBG("data_send=0x%x\n",data_send);
        osal_task_sleep(10);
        if(UPGRADE_SINGLE == upgrade_mode)
        {
            data_check = ~data_send;
            erom_rm(UPGRADE_PARAM_ADDR+offset, &data_check, sizeof(UINT32), 0);
            P2PUPG_DBG("data_check=0x%x\n",data_check);
            if(data_check == data_send)
                return TRUE;
            osal_task_sleep(10);
        }
    }

    if(UPGRADE_SINGLE == upgrade_mode)
        return FALSE;
    return TRUE;
}

static void init_upgrade_param()
{
#if (SYS_SDRAM_SIZE != 2) || defined(_MHEG5_ENABLE_)
    struct sto_device* sto_local_flash_dev = (struct sto_device *)dev_get_by_id(HLD_DEV_TYPE_STO, 0);
    m_UpgradeParam.binary_len = (UINT32)(sto_local_flash_dev->totol_size);
#endif
    if(UPGRADE_MULTI == upgrade_mode)
        m_UpgradeParam.upgrade_mode = UPGRADE_MODE_MUL_NORMAL;
    else
        m_UpgradeParam.upgrade_mode = UPGRADE_MODE_One2One | (UART_DOWNLOAD_SPEED<<8);
}


static void config_uart_speed(UINT8 mode)
{
    if(mode != 1 && mode != 2)
        return;

	*((volatile UINT32 *)(0xB8001308)) = 0;
	osal_task_sleep(100);

    if(1 == mode)
    	*((volatile UINT32 *)(0xB8000074)) = 0x40000000;    // 2M mode
    else
    	*((volatile UINT32 *)(0xB8000074)) = 0x40008000;    // 6M mode
	osal_task_sleep(100); // must delay here

	*((volatile UINT32 *)(0xB8001308)) = 0x08;	
	osal_task_sleep(100);
}

static void erom_download(UINT32 slave_addr, UINT8 *ptr_data_buf, UINT32 total_len)
{
    UINT32 len;

    while(total_len)
    {
        len = (total_len > TRANS_BLOCK_SIZE) ? TRANS_BLOCK_SIZE : total_len;
        erom_wm(slave_addr, ptr_data_buf, len, 1);
        osal_task_sleep(2);
        slave_addr += len;
        ptr_data_buf += len;
        total_len -= len;
    }
}


static BOOL init_slave()
{
	  UINT8 *ptr_data_buf, *ptr_temp_buf;
	  UINT32 ptr_zip_pos;
	  UINT8 zero_buf[16];
	  UINT32 slave_addr;
	  UINT32 total_len, len, chid;
	  int ret;
	  UINT32 i;

	callback_fun(2, 0, "Init slaver...");
	P2PUPG_DBG("init_slave\n");

//     init slave sdram
    for(i=0; i<sizeof(m_SlaveConfig)/sizeof(m_SlaveConfig[0]); i++)
    {
        osal_task_sleep(50);
//        if(0xb8000029 == m_SlaveConfig[i].Address)
//        {
//		if(sys_ic_is_M3101())
//			m_SlaveConfig[i].Data = *((volatile UINT8 *)m_SlaveConfig[i].Address) & 0x07;
//		else
//			m_SlaveConfig[i].Data = *((volatile UINT8 *)m_SlaveConfig[i].Address) & 0x1c;
//        }
        erom_wm(m_SlaveConfig[i].Address, &m_SlaveConfig[i].Data, 1, 0);
    }

//     set upgrade param
    init_upgrade_param();
    for(i=0; i<sizeof(EROM_UPGRADE_PARAM); i+=sizeof(UINT32))
    {
        if(!send_upgrade_param(i))
        {
            callback_fun(2, 0, "send upgrade param failed");
            return FALSE;
        }
            

    }
    P2PUPG_DBG("send_upgrade_param OK\n");

    unsigned long chunk_id = g_upge_feature_config.chip_flashwr;
    ptr_zip_pos = sto_chunk_goto(&chunk_id, 0xFFFFFFFF, 1);
    unsigned long zip_size = sto_fetch_long(ptr_zip_pos + CHUNK_LENGTH);
    ptr_zip_pos += CHUNK_HEADER_SIZE;
    ptr_data_buf = (UINT8 *)bk_buff;   // 48KB for unzip buffer
    ptr_temp_buf = (UINT8 *)(bk_buff + 0xC000);    // 16KB for temp buffer
    P2PUPG_DBG("ptr_zip_pos = 0x%x\n ptr_data_buf = 0x%x\n ptr_temp_buf = 0x%x\n",ptr_zip_pos,ptr_data_buf,ptr_temp_buf);
    if(g_upge_feature_config.enable_lzma_out_read == TRUE)
        ret = un7zip(ptr_zip_pos+SYS_FLASH_BASE_ADDR, zip_size, ptr_temp_buf, 0x4000, ptr_data_buf, 0xC000, NULL);
    else
        ret = un7zip(ptr_zip_pos+SYS_FLASH_BASE_ADDR, ptr_data_buf, ptr_temp_buf);
    P2PUPG_DBG("un7zip ret=%d\n",ret);
    if(ret)
        return FALSE;
    P2PUPG_DBG("un7zip OK");
    MEMCPY(&total_len, ptr_temp_buf, sizeof(unsigned int));
    P2PUPG_DBG("total_len =%d\n",total_len);

    uart_high_speed_config(UART_SPEED_NORMAL);
    // download flashwr
    erom_download(FLASHWR_RUN_ADDR, ptr_data_buf, total_len);
    // init slave config buffer
        P2PUPG_DBG("erom_download1 OK\n");

    MEMSET(zero_buf, 0, sizeof(zero_buf));
    erom_download(FWCFG_START_ADDR, zero_buf, sizeof(zero_buf));
            P2PUPG_DBG("erom_download2 OK\n");

    // download config chunk
    chid = g_upge_feature_config.chip_config;
    if((chid!=0)&&(chid!=0xFFFFFFFF))
    {
        ptr_data_buf = (UINT8 *)sto_chunk_goto(&chid, 0xFFFFFFFF, 1);
        P2PUPG_DBG("ptr_data_buf=0x%x\n",ptr_data_buf);

        if(ptr_data_buf != NULL)
        {
            total_len = sto_fetch_long((unsigned long)(ptr_data_buf+CHUNK_OFFSET));
            erom_download(FWCFG_START_ADDR, ptr_data_buf, total_len);
        }
    }


    if(UPGRADE_SINGLE == upgrade_mode)
    {
        erom_setpc(FLASHWR_RUN_ADDR);
        osal_task_sleep(50);
        sci_mode_set(p2p_uart_id, 115200, SCI_PARITY_EVEN);
        osal_task_sleep(100);
        config_uart_speed(UART_DOWNLOAD_SPEED);
    }

    return TRUE;
}

static UINT32 transfer_mode=0;//0:Multi  1:Single
UINT32 set_transfer_mode(UINT32 mode)
{
	transfer_mode = mode;
}

UINT32 get_transfer_mode()
{
	return transfer_mode;
}

#if ( ((defined _S3281_) || (defined _M3503_)) && (defined(_EROM_UPG_HOST_ENABLE_)) )
static UINT32 erom_upg_mode=1;//0:flash&bl_en  1:flash  2:bl_en
UINT32 set_upgrade_mode(UINT32 mode)
{
	erom_upg_mode = mode;
}

UINT32 get_upgrade_mode()
{
	return erom_upg_mode;
}

static BOOL send_upgrade_param_3281(UINT32 offset)
{
    UINT32 data_check, data_send;
    int retry_times = 3;

    data_send = *((UINT32 *)&m_UpgradeParam + offset/sizeof(UINT32));
    while(retry_times--)
    {
#ifdef _M3503_
        erom_wm(UPGRADE_PARAM_ADDR+offset, &data_send, sizeof(UINT32), 0);
#else //3281
        erom_wm(UPGRADE_PARAM_ADDR_EXT+offset, &data_send, sizeof(UINT32), 0);
#endif
        P2PUPG_DBG("data_send=0x%x\n",data_send);
        osal_task_sleep(10);
        if(UPGRADE_SINGLE == upgrade_mode)
        {
            data_check = ~data_send;
#ifdef _M3503_
            erom_rm(UPGRADE_PARAM_ADDR+offset, &data_check, sizeof(UINT32), 0);
#else //3281
            erom_rm(UPGRADE_PARAM_ADDR_EXT+offset, &data_check, sizeof(UINT32), 0);
#endif
            P2PUPG_DBG("data_check=0x%x\n",data_check);
            if(data_check == data_send)
                return TRUE;
            osal_task_sleep(10);
        }
    }

    if(UPGRADE_SINGLE == upgrade_mode)
        return FALSE;
    return TRUE;
}

static void init_upgrade_param_3281(UINT32 speed_mode)
{
	if(UPGRADE_MULTI == upgrade_mode)
		m_UpgradeParam.upgrade_mode = UPGRADE_MODE_MUL_NORMAL | (speed_mode<<8);
	else
		m_UpgradeParam.upgrade_mode = UPGRADE_MODE_One2One | (speed_mode<<8);
		
	//flash burn?
	if(is_burn_flash_3281())
	{
#ifdef _EROM_UPG_HOST_THREE_LADDER_ENC_SW_UK
        m_UpgradeParam.upgrade_mode |= 0x02<<16;
#else
		m_UpgradeParam.upgrade_mode |= 0x01<<16;
#endif
	}
	else
	{
		m_UpgradeParam.upgrade_mode &= (~(0xff<<16));
	}

	//bloader enc?
	if(is_burn_otp_3281())
	{
#ifdef _EROM_UPG_HOST_THREE_LADDER_ENC_SW_UK
        m_UpgradeParam.upgrade_mode |= 0x02<<24;
#else	
		m_UpgradeParam.upgrade_mode |= 0x01<<24;
#endif
	}
	else
	{
		m_UpgradeParam.upgrade_mode &= (~(0xff<<24));
	}

	m_UpgradeParam.binary_len = FW_LEN;
	
}

#ifdef _USE_32M_MEM_
#define CMD_ARRAY_SIZE 54 
unsigned long MemInitCmd[CMD_ARRAY_SIZE*3] = { 
0x4, 0xB80000fc, 0x00031234,
0x4, 0xB8000074, 0x00060033,
0x4, 0xB8000870, 0x00010000,
0x4, 0xB8000874, 0x64228077,
0x4, 0xb8000878, 0x00022000,
0x4, 0xb800087c, 0x00022000,
0x4, 0xb8000880, 0x00044000,
0x4, 0xb8000884, 0x00044000,
0x4, 0xb8000888, 0x00044010,
0x2, 0xb8000082, 0x0519,
0x1, 0xb8000081, 0x00,
0x2, 0xb8000084, 0x3505,
0x1, 0xb8000080, 0x02,
0x1, 0xb8000087, 0x01,
0x1, 0xb8000080, 0x05,
0x1, 0xb8000087, 0x09,
0x1, 0xb8000080, 0x05,
0x1, 0xb8000087, 0x01,
0x1, 0xb8000080, 0x05,
0x1, 0xb8000087, 0x11,
0x1, 0xb8000080, 0x05,
0x2, 0xb8000086, 0x0533,
0x1, 0xb8000080, 0x01,
0x1, 0xb8000080, 0x02,
0x1, 0xb8000086, 0x33,
0x1, 0xb8000080, 0x03,
0x1, 0xb8000080, 0x03,
0x1, 0xb8000080, 0x03,
0x1, 0xb8000080, 0x03,
0x1, 0xb8000081, 0x07,
0x1, 0xb8000080, 0x08,
0x2, 0xb8000084, 0x3755,
};
#else
#define CMD_ARRAY_SIZE 54 
unsigned long MemInitCmd[CMD_ARRAY_SIZE*3] = { 
0x4, 0xB80000fc, 0x00031234,
0x4, 0xB8000074, 0x00060033,
0x4, 0xB8000870, 0x00010000,
0x4, 0xB8000874, 0x64228077,
0x4, 0xb8000878, 0x00022000,
0x4, 0xb800087c, 0x00022000,
0x4, 0xb8000880, 0x00044000,
0x4, 0xb8000884, 0x00044000,
0x4, 0xb8000888, 0x00044010,
0x2, 0xb8000082, 0x051a,
0x1, 0xb8000081, 0x00,
0x2, 0xb8000084, 0x3505,
0x1, 0xb8000080, 0x02,
0x1, 0xb8000087, 0x01,
0x1, 0xb8000080, 0x05,
0x1, 0xb8000087, 0x09,
0x1, 0xb8000080, 0x05,
0x1, 0xb8000087, 0x01,
0x1, 0xb8000080, 0x05,
0x1, 0xb8000087, 0x11,
0x1, 0xb8000080, 0x05,
0x2, 0xb8000086, 0x0533,
0x1, 0xb8000080, 0x01,
0x1, 0xb8000080, 0x02,
0x1, 0xb8000086, 0x33,
0x1, 0xb8000080, 0x03,
0x1, 0xb8000080, 0x03,
0x1, 0xb8000080, 0x03,
0x1, 0xb8000080, 0x03,
0x1, 0xb8000081, 0x07,
0x1, 0xb8000080, 0x08,
0x2, 0xb8000084, 0x3755,
};
#endif

static void meminit(void)
{
  int i;
  for (i = 0; i < CMD_ARRAY_SIZE*3; i += 3){
    switch(MemInitCmd[i]){
      case 0x1:
        erom_rw(MemInitCmd[i + 1],&(MemInitCmd[i + 2]),1,0,0);
        break;
       case 0x2:  
        erom_rw(MemInitCmd[i + 1],&(MemInitCmd[i + 2]),2,0,0);
        break;
       case 0x4:
        erom_rw(MemInitCmd[i + 1],&(MemInitCmd[i + 2]),4,0,0);
        break;
       case 0x14:
        erom_rw(MemInitCmd[i + 1],&(MemInitCmd[i + 2]),1,0,1);
        break;
      default:
        break;
    }
    osal_delay(100);
  }
}

static BOOL is_burn_flash_3281()
{
	UINT32 erom_upgrade_mode = get_upgrade_mode();
	if(0==erom_upgrade_mode || 1==erom_upgrade_mode)
		return TRUE;
	else 
		return FALSE;
}

static BOOL is_burn_otp_3281()
{
	UINT32 erom_upgrade_mode = get_upgrade_mode();
	if(0==erom_upgrade_mode || 2==erom_upgrade_mode)
		return TRUE;
	else
		return FALSE;
}

static BOOL init_slave_3281()
{
	  UINT8 *ptr_data_buf, *ptr_temp_buf;
	  UINT32 ptr_zip_pos;
	  UINT8 zero_buf[16];
	  UINT32 slave_addr;
	  UINT32 total_len, len, chid;
	  int ret;
	  UINT32 i;
	  UINT32 speed_mode;

	callback_fun(2, 0, "Init slaver...");
	P2PUPG_DBG("init_slave\n");

	//init slave sdram
   	meminit();
    	P2PUPG_DBG("ddr init end\n");//evan test
    	
	//download eromclient
	unsigned long erom_chunk_id = EROM_CLIENT_ID;
	CHUNK_HEADER chunk_hdr;	
	unsigned long chunk_data_len;
	char* eromclient_addr = EROM_CLIENT_ADDR;
	if(sto_get_chunk_header(erom_chunk_id,&chunk_hdr)!=0)
	{
		chunk_data_len= chunk_hdr.len - CHUNK_HEADER_SIZE + 16;
		sto_get_data( (struct sto_device *)dev_get_by_id(HLD_DEV_TYPE_STO, 0), eromclient_addr,
									(UINT32)sto_chunk_goto(&erom_chunk_id,0xFFFFFFFF,1) + CHUNK_HEADER_SIZE, chunk_data_len);		
	}	
	erom_download(EROMCLIENT_RUN_ADDR, eromclient_addr, chunk_data_len);

	//download eromclient_see
	unsigned long see_erom_chunk_id = EROM_SEE_CLIENT_ID;
	CHUNK_HEADER see_chunk_hdr;	
	unsigned long see_chunk_data_len;
	char* see_eromclient_addr = EROM_SEE_CLIENT_ADDR;
	if(sto_get_chunk_header(see_erom_chunk_id,&see_chunk_hdr)!=0)
	{
		see_chunk_data_len = see_chunk_hdr.len - CHUNK_HEADER_SIZE + 16;
		sto_get_data( (struct sto_device *)dev_get_by_id(HLD_DEV_TYPE_STO, 0), see_eromclient_addr,
									(UINT32)sto_chunk_goto(&see_erom_chunk_id,0xFFFFFFFF,1) + CHUNK_HEADER_SIZE, see_chunk_data_len);		
	}	
	erom_download(EROMCLIENT_SEE_RUN_ADDR, see_eromclient_addr, see_chunk_data_len);

	P2PUPG_DBG("erom_download1 OK\n");
	

	//set upgrade param
	//speed_mode = ((UPGRADE_SINGLE == upgrade_mode)?UART_SPEED_1687500:UART_SPEED_115200);
	speed_mode = UART_SPEED_115200;//UART_SPEED_562500;//UART_SPEED_115200;
    	init_upgrade_param_3281(speed_mode);
	for(i=0; i<sizeof(EROM_UPGRADE_PARAM); i+=sizeof(UINT32))
    	{
		if(!send_upgrade_param_3281(i))
		{
			callback_fun(2, 0, "send upgrade param failed");
			return FALSE;
		}
    	}

	
	//if(UPGRADE_SINGLE == upgrade_mode)
	{
		erom_setpc(EROMCLIENT_RUN_ADDR);
		osal_task_sleep(1000);
		sci_mode_set(p2p_uart_id, 115200, SCI_PARITY_EVEN);
		osal_task_sleep(100);
		config_uart_speed(UART_DOWNLOAD_SPEED);
	}

	sci_16550uart_set_high_speed_mode_3281(SCI_FOR_RS232, speed_mode);
	
	callback_fun(2, 0, "Init slaver OK.");
	
	return TRUE;
}
#endif

#endif


static INT32 p2p_download()
{
	UINT32 result = SUCCESS;
	INT32 i;
	
	MG_Setup_CRC_Table();
	
	/* Check sci port */
	callback_fun(3,0,"Checking serial port...");

	result = cmd_comtest(&g_protocol_version, NULL, get_exit_key);
	if(result != SUCCESS)
	{
		pan_display_error(result);
		callback_fun(2,0,"Connect failed.");
		return !SUCCESS;
	}

    	p2p_delay();
	callback_fun(2,0,"Collecting version information...");
	if((result = cmd_version(&g_protocol_version)) != SUCCESS)
	{
		pan_display_error(result);
		callback_fun(2, 0, "Upgrade failed, please try again.");
		return !SUCCESS;
	}
	
	
	p2p_delay();
	callback_fun(2,0,"Compare Slave Reorg...");
#if((defined _VMX_CA_ENABLE_) && ((defined _S3281_) ||(defined _M3503_)) && (defined(_EROM_UPG_HOST_ENABLE_))) 	
	if((result =SlaveReorg_3281(callback_fun)) != SUCCESS)
#else
	if((result =SlaveReorg(callback_fun)) != SUCCESS)
#endif
	{
		callback_fun(2,0,"Upgrade failed, please try again.");
		return !SUCCESS;
	}
	p2p_delay();

#if ( ((defined _S3281_) || (defined _M3503_)) && (defined(_EROM_UPG_HOST_ENABLE_)))
	UINT32 addr = 0x0;
#else
	UINT32 addr = 0x0;
	if(pslave_reorg_list[0].type == 2)  //transfer bootloader
	{
		addr = 0x0;
	}
	else
	{
#if (SYS_PROJECT_FE	== PROJECT_FE_DVBT && SYS_SDRAM_SIZE == 2)
		addr = 0x7800;
#else
#if (SYS_CHIP_MODULE == ALI_M3327C && SYS_SDRAM_SIZE == 2)
		//addr = 0xc000;
		//add logo data, so the address is changed
        addr = 0x8000;
#else
		addr = pslave_list[0].offset;
#endif
#endif
	}
#endif		
	if((result = cmd_address(addr)) != SUCCESS)
	{
		pan_display_error(result);
		callback_fun(2, 0, "Upgrade failed, please try again.");
		return !SUCCESS;
	}

	trans_size = 0;
	prog = 0;
	callback_fun(3,0,"Transfering data...");
#if (SYS_CHIP_MODULE != ALI_M3327C || SYS_SDRAM_SIZE != 2)
	pan_display(LV_pPanDev,  "u0  ", 4);
#endif

#if((!defined _VMX_CA_ENABLE_) && ((defined _S3281_) ||(defined _M3503_)) && (defined(_EROM_UPG_HOST_ENABLE_)) )
	result = command_transfer_3281_new(callback_fun);
	if(result != SUCCESS)
	{
		pan_display_error(result);
		callback_fun(2,0,"transfer failed, please try again.");
		return !SUCCESS;
	}
#else
	for(i=0; i<slave_reorg_number;i++)
	{
		p2p_delay();

		if(pslave_reorg_list[i].type==1) //move
		{
			if(i==0)  continue;
			result = command_move(pslave_reorg_list[i].index, pslave_reorg_list[i].offset, callback_fun);
			if(result != SUCCESS)
			{
				pan_display_error(result);
				callback_fun(2,0,"move failed, please try again.");
				return !SUCCESS;
			}
			
		}
		else //transfer
		{			
			result = command_transfer(pslave_reorg_list[i].index,callback_fun);
			
			if(result != SUCCESS)
			{
				pan_display_error(result);
				callback_fun(2,0,"transfer failed, please try again.");
				return !SUCCESS;
			}
		}
	}
#endif

#if (SYS_CHIP_MODULE != ALI_M3327C || SYS_SDRAM_SIZE != 2)
	pan_display(LV_pPanDev,  "100 ", 4);
#endif
    	p2p_delay();

	return SUCCESS;

}

static INT32 p2p_burn()
{
	UINT32 result = SUCCESS;
	BOOL bReboot =TRUE;

	/* Send command to burn flash */
	callback_fun(3,0,"Burning flash...");
	pan_display(LV_pPanDev,  "burn ", 4);
		
#if (SYS_CHIP_MODULE != ALI_M3327C || SYS_SDRAM_SIZE != 2)
	pan_display(LV_pPanDev,  "b0  ", 4);
#endif

	if((result = command_burn_new(callback_fun, bReboot)) != SUCCESS)
	{
		pan_display_error(result);
		callback_fun(2,0,"Upgrade failed, please try again.");
		return !SUCCESS;
	}
		
#if (SYS_CHIP_MODULE != ALI_M3327C || SYS_SDRAM_SIZE != 2)
	pan_display(LV_pPanDev,  "100 ", 4);
#endif
	pan_display(LV_pPanDev,  "end ", 4);
	
	/*reboot slaver*/
	if(bReboot)
	{
		callback_fun(2,0,"Rebooting slaver...");
	    if(command_reboot(callback_fun) != SUCCESS)
	    {
	        callback_fun(2,0,"Upgrade failed, please try again.");
	        return !SUCCESS;
	    }
	}

	return SUCCESS;

}

#ifdef ENABLE_EROM
#if 0
static int erom_cmd_wm(void *buf, unsigned long len)
{    
	unsigned long i;
osal_task_dispatch_off();
    for(i=0;i<len;i++)
    {
		//send data
	    sci_write(p2p_uart_id, *((unsigned char *)buf + i));	
        osal_delay(20);//evan test
	}	
osal_task_dispatch_on();
	
	return SUCCESS;
}
#else
static int erom_cmd_wm(void *buf, unsigned long len)
{    
	unsigned long i;
osal_interrupt_disable();
    for(i=0;i<len;i++)
    {
		//send data
	    sci_16550uart_hight_speed_mode_write(p2p_uart_id, *((unsigned char *)buf + i));	
        //osal_delay(20);//evan test
	}	
osal_interrupt_enable();
	
	return SUCCESS;
}
#endif
static INT32 p2m_download()
{
#if 1
	UINT32 result = SUCCESS;
	UINT32 trans_len, len;
	UINT32 slave_addr, master_addr, master_addr_bak;
    UINT32 i = 0;
    UINT32 crc = 0;
    

	master_addr = FW_ADDR;
    master_addr_bak = master_addr;
	slave_addr = IMAGE_START_ADDR;

    //evan test
    //m_UpgradeParam.binary_len = 0x100000;

	//init UpgradeProgress() param
	trans_size = 0;
	prog = 0;
	slave_reorg_size = m_UpgradeParam.binary_len;

    MG_Setup_CRC_Table();

	callback_fun(3, 0, "Transfering data...");

/**********************************************************
| data_len | data | crc |
**********************************************************/
    p2p_delay();
    //data_len
    erom_cmd_wm(&(m_UpgradeParam.binary_len), 4);
    //data
    for(trans_len=0; trans_len<m_UpgradeParam.binary_len; trans_len+=len)
    {
	 //check if user cancel data transfer
	 if(1==get_exit_key())
	     return ERROR_USERABORT;
		
        len = TRANS_BLOCK_SIZE;
        if(len > (m_UpgradeParam.binary_len - trans_len))
            len = m_UpgradeParam.binary_len - trans_len;
        //erom_wm(slave_addr, (void *)master_addr, len, 1);
        erom_cmd_wm((void *)master_addr, len);
        slave_addr += len;
        master_addr += len;

	UpgradeProgress(len);
       
        //osal_task_sleep(2);
    }    
    crc = MG_Table_Driven_CRC(0xFFFFFFFF, (UINT8 *)master_addr_bak, m_UpgradeParam.binary_len);
    //crc
    erom_cmd_wm(&crc, 4);

    P2PUPG_DBG("crc:%d\n", crc);
#endif	

    return SUCCESS;
}

static INT32 p2m_burn()
{
#if 1
    int i, count;

    callback_fun(3, 0, "Burning flash...");
    //erom_setpc(EROMCLIENT_RUN_ADDR);
    osal_task_sleep(1000);

    count = (m_UpgradeParam.binary_len+0xFFFF)/0x10000 + 1;
    for(i=1; i<=count; i++)
	{
		osal_task_sleep(500);
              callback_fun(1, (i*100)/count, NULL);
	}
#endif
    return SUCCESS;
}
#endif


// type = 1 normal upgrade
// type = 2 3 burn only send command not care return parameter & not reboot after burn
INT32 sys_upgrade_process(void (*callback)(INT32 type, INT32 process, UINT8 *str), UINT32 (*GetExitKey)(void), int nType)
{
	UINT32 result = SUCCESS;

	typedef INT32 (*PFN_DOWNLOAD)();
	typedef INT32 (*PFN_BURN)();
#ifdef ENABLE_EROM	
	upgrade_mode = get_transfer_mode();
	PFN_DOWNLOAD pfn_download[2] = {p2m_download, p2p_download};
	PFN_BURN pfn_burn[2] = {p2m_burn, p2p_burn};
	int sel = (UPGRADE_MULTI == upgrade_mode) ? 0 : 1;
#else
	PFN_DOWNLOAD pfn_download[1] = {p2p_download};
	PFN_BURN pfn_burn[1] = {p2p_burn};
	int sel = 0;
#endif

	get_exit_key = GetExitKey;
	callback_fun = callback;
	
	LV_pPanDev = (struct pan_device *) dev_get_by_type(NULL, HLD_DEV_TYPE_PAN);
	if(NULL == LV_pPanDev)
	{
		PRINTF("dev_get_by_name failed\n");
		return !SUCCESS;
	}
	if(pan_open(LV_pPanDev)!=SUCCESS)
	{
		PRINTF("pan_open failed\n");
		LV_pPanDev = NULL;
		//return !SUCCESS;
	}

	//pan_display(LV_pPanDev,  "up9 ", 4);
#ifdef THREE_DIGITS_PANEL
	pan_display(LV_pPanDev,  " up9", 4);
#else
	pan_display(LV_pPanDev,  "up9 ", 4);
#endif

#ifdef ENABLE_EROM
    init_buffer();
//    uart_reset();
    osal_task_sleep(100);
    uart_high_speed_config(UART_SPEED_NORMAL);
#if ( ((defined _S3281_) || (defined _M3503_)) && (defined(_EROM_UPG_HOST_ENABLE_))) //reset to 115200
	sci_16550uart_set_high_speed_mode_3281(SCI_FOR_RS232, UART_SPEED_115200);
#endif

    do
    {
        if(!sync_slave((UPGRADE_MULTI==upgrade_mode)?M2S_MODE:P2P_MODE, 1000))
            return !SUCCESS; ;

#if ( ((defined _S3281_) || (defined _M3503_)) && (defined(_EROM_UPG_HOST_ENABLE_)))   	 
	        if(!init_slave_3281()) // 
	            return !SUCCESS;;
#else
		if(!init_slave()) // 
	            return !SUCCESS;;
#endif

	}while(0);
#endif

	//download
#if ( ((defined _S3281_) || (defined _M3503_)) && (defined(_EROM_UPG_HOST_ENABLE_)))
	if(is_burn_flash_3281())
	{
#endif
		if(SUCCESS!=pfn_download[sel]())
			return !SUCCESS;

		//burn
		if(SUCCESS!=pfn_burn[sel]())
			return !SUCCESS;
		
#if ( ((defined _S3281_) || (defined _M3503_)) && (defined(_EROM_UPG_HOST_ENABLE_)))
	}
	else if(is_burn_otp_3281())
	{
		callback_fun(3, 0, "Burning otp...");
    #if 0    
		if(UPGRADE_MULTI == upgrade_mode)
			erom_setpc(EROMCLIENT_RUN_ADDR);
    #endif        
		osal_task_sleep(5000);
	}
#endif		
	
#ifdef ENABLE_EROM
	free_buffer();
#endif

	callback_fun(2, 0, "Upgrade successful!");

	return SUCCESS;
}

INT32 sys_upgrade(void (*callback)(INT32 type, INT32 process, UINT8 *str), UINT32 (*GetExitKey)(void))
{
	return sys_upgrade_process(callback, GetExitKey, 1);
}

#if ENABLE_UNUSED_FUNCTION
INT32 sys_upgrade2(void (*callback)(INT32 type, INT32 process, UINT8 *str), UINT32 (*GetExitKey)(void))
{
	return sys_upgrade_process(callback, GetExitKey, 2);
}

INT32 sys_upgrade3(char* ledstr, void (*callback)(INT32 type, INT32 process, UINT8 *str), UINT32 (*GetExitKey)(void))
{
	return sys_upgrade_process(callback, GetExitKey, 3);
}

static INT32 command_transferraw (void (*callback)(INT32 type, INT32 process, UINT8 *str))
{
	UINT32 transLen = SYS_FLASH_SIZE;
	slave_reorg_size = SYS_FLASH_SIZE;
	BYTE *p = ((unsigned char *)FLASH_BASE);

	return (INT32)cmd_transfer(p, transLen, UpgradeProgress, get_exit_key);
}


/* Updata whole flash with LED support only */
INT32 sys_upgrade4(char* ledstr,void (*callback)(INT32 type, INT32 process, UINT8 *str), UINT32 (*GetExitKey)(void))
{
	UINT32 result = SUCCESS;
	INT32 i;
	INT32 retry_count=0;

	get_exit_key = GetExitKey;
	callback_fun = callback;

	
	LV_pPanDev = (struct pan_device *) dev_get_by_type(NULL, HLD_DEV_TYPE_PAN);
	if(NULL == LV_pPanDev)
	{
		PRINTF("dev_get_by_name failed\n");
		return !SUCCESS;
	}
	if(pan_open(LV_pPanDev)!=SUCCESS)
	{
		PRINTF("pan_open failed\n");
		return !SUCCESS;
	}

	//pan_display(LV_pPanDev,  "up9 ", 4);
#ifdef THREE_DIGITS_PANEL
	pan_display(LV_pPanDev,  " up9", 4);
#else
	pan_display(LV_pPanDev,  "up9 ", 4);
#endif

	MG_Setup_CRC_Table();

	/* Check sci port */
	callback(3,0,"Checking serial port...");

	result = cmd_comtest(&g_protocol_version, NULL, GetExitKey);
	if(result != SUCCESS)
	{
		pan_display_error(result);
		callback(2,0,"Connect failed.");
		return !SUCCESS;
	}

    	p2p_delay();
	callback(2,0,"Collecting version information...");
	if((result = cmd_version(&g_protocol_version)) != SUCCESS)
	{
		pan_display_error(result);
		callback(2, 0, "Upgrade failed, please try again.");
		return !SUCCESS;
	}
	
	p2p_delay();


	if((result = cmd_address(0x0)) != SUCCESS)
	{
		pan_display_error(result);
		callback(2, 0, "Upgrade failed, please try again.");
		return !SUCCESS;
	}

	trans_size = 0;
	prog = 0;
	callback(3,0,"Transfering data...");
#if (SYS_CHIP_MODULE != ALI_M3327C || SYS_SDRAM_SIZE != 2)
	pan_display(LV_pPanDev,  "u0  ", 4);
#endif
	result = command_transferraw(callback);
	if(result != SUCCESS)
   	{
		callback(2,0,"Upgrade failed, please try again.");
		return !SUCCESS;
   	}
#if (SYS_CHIP_MODULE != ALI_M3327C || SYS_SDRAM_SIZE != 2)
	pan_display(LV_pPanDev,  "u100 ", 4);
#endif

    	p2p_delay();
	/* Send command to burn flash */
	callback(3,0,"Burning flash...");
#if (SYS_CHIP_MODULE != ALI_M3327C || SYS_SDRAM_SIZE != 2)
	pan_display(LV_pPanDev,  "b0  ", 4);
#endif
	if((result = command_burn_new(callback, FALSE)) != SUCCESS)
	{
		pan_display_error(result);
		callback(2,0,"Upgrade failed, please try again.");
		return !SUCCESS;
	}

#if (SYS_CHIP_MODULE != ALI_M3327C || SYS_SDRAM_SIZE != 2)
	pan_display(LV_pPanDev,  "100 ", 4);
#endif

	callback(2, 0, "Upgrade successful!");

	return SUCCESS;
}
#endif



